﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using DocumentsTagger.DM;

namespace DocumentsTagger.DAL
{
    /// <summary>
    /// Implements the ITaggerDal interface.
    /// Stores the tag, document and config information within XML files, for more universal use.
    /// </summary>
    public class TaggerXMLDal:ITaggerDal
    {
        #region members
        private const string CONFIGURATION_XML_FILENAME = @"Config.xml";
        private const string DOCUMENTS_XML_FILENAME = @"Documents.xml";
        private const string TAG_XML_FILENAME = @"Tags.xml";
        private const string APP_FOLDER_NAME = @"DocumentsTagger";

        private static TaggerXMLDal s_SingletonItem = null;

        private readonly string r_ConfigurationXMLPath;
        private readonly string r_DocumentsXMLPath;
        private readonly string r_TagsXMLPath;

        private object m_SyncLocker = new object();
        #endregion

        #region ctor
        /// <summary>
        /// creates a dal object for handling xml.
        /// </summary>
        private TaggerXMLDal()
        {
            string appDataDir = GetUserDataPath();

            r_ConfigurationXMLPath = GetConfigurationXmlPath(appDataDir);
            r_DocumentsXMLPath = GetDocumentsXmlPath(appDataDir);
            r_TagsXMLPath = GetTagsXmlPath(appDataDir);
        }
        #endregion

        #region methods
        #region public methods
        /// <summary>
        /// Gets an instance of TaggerXMLDal.
        /// </summary>
        /// <returns>a singleton object of TaggerXMLDal</returns>
        public static TaggerXMLDal GetInstance()
        {
            if (null == s_SingletonItem)
            {
                s_SingletonItem = new TaggerXMLDal();
            }

            return s_SingletonItem;
        }

        #endregion 

        #region public interfaced methods
        /// <summary>
        /// returns the directories scanned by the system
        /// </summary>
        /// <returns>List of scanned directories</returns>
        public List<String> GetScannedDirectories()
        {
            List<String> scannedDirs = new List<string>();
            XElement xml;
            lock (m_SyncLocker)
            {
                xml = XElement.Load(r_ConfigurationXMLPath);
            }

            var query = xml.Element("ScannedDirectories").Elements("Directory");
            foreach (var rec in query)
            {
                scannedDirs.Add(rec.Value);
            }

            return scannedDirs;
        }

        /// <summary>
        /// Add scanned directory
        /// </summary>
        /// <param name="path">a path of the directory to scan</param>
        public void AddScannedDirectory(string path)
        {
            XElement xml;
            lock (m_SyncLocker)
            {
                xml = XElement.Load(r_ConfigurationXMLPath);
            }
            XElement val = xml.Element("ScannedDirectories").Elements("Directory").Where(item => item.Value == path).FirstOrDefault();

            if (val == null)
            {
                xml.Element("ScannedDirectories").Add(new XElement("Directory", path));
            }

            lock (m_SyncLocker)
            {
                xml.Save(r_ConfigurationXMLPath);
            }
        }

        /// <summary>
        /// remove scanned directory
        /// </summary>
        /// <param name="path">a path of the directory to remove from scanning</param>
        public void RemoveScannedDirectory(string path)
        {
            XElement xml;
            lock (m_SyncLocker)
            {
                xml = XElement.Load(r_ConfigurationXMLPath);
            }
            XElement val = xml.Element("ScannedDirectories").Elements("Directory").Where(item => item.Value == path).FirstOrDefault();

            if (val != null)
            {
                val.Remove();
            }

            lock (m_SyncLocker)
            {
                xml.Save(r_ConfigurationXMLPath);
            }
        }

        public void AddDocument(Document doc)
        {
            AddDocument(doc, null, null, null);
        }

        public void AddDocument(Document doc, List<Tag> acceptedTagsList, List<Tag> suggestedTagsList, List<Tag> declinedTagsList)
        {
            string path = doc.FilePath;
            string fileName = doc.FileName;
            XElement xml;
            lock (m_SyncLocker)
            {
                xml = XElement.Load(r_DocumentsXMLPath);
            }
            var q = from c in xml.Descendants("Document")
                    where (string)c.Element("Path") == path
                       && (string)c.Element("FileName") == fileName
                    select c;

            if (q.Count() == 0)
            {
                List<XElement> acceptedTagsElm = new List<XElement>();
                List<XElement> declinedTagsElm = new List<XElement>();
                List<XElement> suggestedTagsElm = new List<XElement>();
                if (acceptedTagsList != null)
                {
                    foreach (Tag tag in acceptedTagsList)
                    {
                        acceptedTagsElm.Add(new XElement("Tag", tag.Name));
                    }
                }
                if (declinedTagsList != null)
                {
                    foreach (Tag tag in declinedTagsList)
                    {
                        declinedTagsElm.Add(new XElement("Tag", tag.Name));
                    }
                }
                if (suggestedTagsList != null)
                {
                    foreach (Tag tag in suggestedTagsList)
                    {
                        suggestedTagsElm.Add(new XElement("Tag", tag.Name));
                    }
                }
                xml.Add(
                    new XElement("Document",
                        new XElement("FileName", fileName),
                        new XElement("Path", path),
                        new XElement("AcceptedTags", acceptedTagsElm.ToArray()),
                        new XElement("SuggestedTags", suggestedTagsElm.ToArray()),
                        new XElement("DeclinedTags", declinedTagsElm.ToArray())
                        )
                    );
            }

            lock (m_SyncLocker)
            {
                xml.Save(r_DocumentsXMLPath);
            }
        }

        public List<Document> GetDocuments()
        {
            List<Document> documentsList = new List<Document>();
            try
            {
                XElement xml;
                lock (m_SyncLocker)
                {
                    xml = XElement.Load(r_DocumentsXMLPath);
                }

                var query = from doc in xml.Elements("Document")
                            select doc;

                foreach (var doc in query)
                {
                    Document NewDoc = DocumentsFactory.GetDocument(doc.Element("Path").Value, doc.Element("FileName").Value);
                    foreach (XElement xmlTagParent in doc.Elements("AcceptedTags"))
                    {
                        foreach (XElement xmlTag in xmlTagParent.Elements("Tag"))
                        {
                            NewDoc.AddAcceptedTag(TagsFactory.GetTag(xmlTag.Value));

                        }
                    }
                    foreach (XElement xmlTagParent in doc.Elements("SuggestedTags"))
                    {
                        foreach (XElement xmlTag in xmlTagParent.Elements("Tag"))
                        {
                            NewDoc.AddSuggestedTag(TagsFactory.GetTag(xmlTag.Value));

                        }
                    }

                    foreach (XElement xmlTagParent in doc.Elements("DeclinedTags"))
                    {
                        foreach (XElement xmlTag in xmlTagParent.Elements("Tag"))
                        {
                            NewDoc.AddDeclinedTag(TagsFactory.GetTag(xmlTag.Value));

                        }
                    }
                    documentsList.Add(NewDoc);
                }
            }
            catch
            { }
            return documentsList;
        }

        public List<Document> GetDocumentsByTag(Tag tag)
        {
            List<Document> res = new List<Document>();
            XElement xml;
            lock (m_SyncLocker)
            {
                xml = XElement.Load(r_DocumentsXMLPath);
            }
            var q = xml.Elements("Document").Where(u => u.Element("AcceptedTags").Elements("Tag").Where(v => v.Value == tag.Name).Count() == 1);
            foreach (XElement node in q)
            {
                Document doc = DocumentsFactory.GetDocument(node.Element("Path").Value, node.Element("FileName").Value);

                foreach (XElement xmlTagParent in node.Elements("AcceptedTags"))
                {
                    foreach (XElement xmlTag in xmlTagParent.Elements("Tag"))
                    {
                        doc.AddAcceptedTag(TagsFactory.GetTag(xmlTag.Value));
                    }
                }

                foreach (XElement xmlTagParent in node.Elements("SuggestedTags"))
                {
                    foreach (XElement xmlTag in xmlTagParent.Elements("Tag"))
                    {
                        doc.AddSuggestedTag(TagsFactory.GetTag(xmlTag.Value));
                    }
                }

                foreach (XElement xmlTagParent in node.Elements("DeclinedTags"))
                {
                    foreach (XElement xmlTag in xmlTagParent.Elements("Tag"))
                    {
                        doc.AddDeclinedTag(TagsFactory.GetTag(xmlTag.Value));
                    }
                }

                res.Add(doc);
            }

            return res;
        }

        public List<Document> GetDocumentsByAcceptedTag(Tag tag)
        {
            List<Document> res = new List<Document>();
            XElement xml;
            lock (m_SyncLocker)
            {
                xml = XElement.Load(r_DocumentsXMLPath);
            }
            var q = xml.Elements("Document").Where(u => u.Element("AcceptedTags").Elements("Tag").Where(v => v.Value == tag.Name).Count() == 1);
            foreach (XElement node in q)
            {
                Document doc = DocumentsFactory.GetDocument(node.Element("Path").Value, node.Element("FileName").Value);

                foreach (XElement xmlTagParent in node.Elements("AcceptedTags"))
                {
                    foreach (XElement xmlTag in xmlTagParent.Elements("Tag"))
                    {
                        doc.AddAcceptedTag(TagsFactory.GetTag(xmlTag.Value));
                    }
                }

                foreach (XElement xmlTagParent in node.Elements("SuggestedTags"))
                {
                    foreach (XElement xmlTag in xmlTagParent.Elements("Tag"))
                    {
                        doc.AddSuggestedTag(TagsFactory.GetTag(xmlTag.Value));
                    }
                }

                foreach (XElement xmlTagParent in node.Elements("DeclinedTags"))
                {
                    foreach (XElement xmlTag in xmlTagParent.Elements("Tag"))
                    {
                        doc.AddDeclinedTag(TagsFactory.GetTag(xmlTag.Value));
                    }
                }

                res.Add(doc);
            }

            return res;
        }

        public List<Document> GetDocumentsByDeclinedTag(Tag tag)
        {
            List<Document> res = new List<Document>();
            XElement xml;
            lock (m_SyncLocker)
            {
                xml = XElement.Load(r_DocumentsXMLPath);
            }
            var q = xml.Elements("Document").Where(u => u.Element("DeclinedTags").Elements("Tag").Where(v => v.Value == tag.Name).Count() == 1);
            foreach (XElement node in q)
            {
                Document doc = DocumentsFactory.GetDocument(node.Element("Path").Value, node.Element("FileName").Value);

                foreach (XElement xmlTagParent in node.Elements("AcceptedTags"))
                {
                    foreach (XElement xmlTag in xmlTagParent.Elements("Tag"))
                    {
                        doc.AddAcceptedTag(TagsFactory.GetTag(xmlTag.Value));
                    }
                }

                foreach (XElement xmlTagParent in node.Elements("SuggestedTags"))
                {
                    foreach (XElement xmlTag in xmlTagParent.Elements("Tag"))
                    {
                        doc.AddSuggestedTag(TagsFactory.GetTag(xmlTag.Value));
                    }
                }

                foreach (XElement xmlTagParent in node.Elements("DeclinedTags"))
                {
                    foreach (XElement xmlTag in xmlTagParent.Elements("Tag"))
                    {
                        doc.AddDeclinedTag(TagsFactory.GetTag(xmlTag.Value));
                    }
                }

                res.Add(doc);
            }

            return res;
        }

        public List<Tag> GetTags()
        {
            List<Tag> tagsList = new List<Tag>();
            XElement xml;
            lock (m_SyncLocker)
            {
                xml = XElement.Load(r_TagsXMLPath);
            }
            var q = from c in xml.Descendants("Tag")
                    select c;

            foreach (var item in q)
            {
                tagsList.Add(TagsFactory.GetTag(item.Value));
            }

            xml = null;
            return tagsList;
        }

        public void AddTag(Tag tag)
        {
            string tagValue = tag.Name;
            XElement xml;
            lock (m_SyncLocker)
            {
                xml = XElement.Load(r_TagsXMLPath);
            }
            var q = from c in xml.Descendants("Tag")
                    where c.Value == tagValue
                    select c;

            if (q.Count() == 0)
            {
                xml.Add(
                    new XElement("Tag", tagValue)
                    );
            }

            lock (m_SyncLocker)
            {
                xml.Save(r_TagsXMLPath);
            }
        }

        public void CreateEmptyDB()
        {
            string appDataDir = GetUserDataPath();
            CreateEmptyTagsXmlFile(Path.Combine(appDataDir, TAG_XML_FILENAME));
            CreateEmptyDocumentsXmlFile(Path.Combine(appDataDir, DOCUMENTS_XML_FILENAME));
            CreateEmptyConfigXmlFile(Path.Combine(appDataDir, CONFIGURATION_XML_FILENAME));
        }

        public bool DocumentExists(string PathToFile)
        {
            bool exists = false;
            string fileName = Path.GetFileName(PathToFile);
            string filePath = Path.GetDirectoryName(PathToFile);

            List<Document> documentsList = new List<Document>();
            XElement xml;
            lock (m_SyncLocker)
            {
                xml = XElement.Load(r_DocumentsXMLPath);
            }

            IEnumerable<XElement> q =
                from doc in xml.Elements("Document")
                where doc.Element("FileName").Value == fileName
                  && doc.Element("Path").Value == filePath
                select doc;

            if (q.Count() > 0)
            {
                exists = true;
            }

            return exists;
        }

        public void RemoveDocument(Document doc)
        {
            string path = doc.FilePath;
            string fileName = doc.FileName;
            XElement xml;
            lock (m_SyncLocker)
            {
                xml = XElement.Load(r_DocumentsXMLPath);
            }
            var q = from c in xml.Descendants("Document")
                    where (string)c.Element("Path") == path
                        && (string)c.Element("FileName") == fileName
                    select c;

            if (q.Count() != 0)
            {
                q.Remove();
            }

            lock (m_SyncLocker)
            {
                xml.Save(r_DocumentsXMLPath);
            }
        }

        public bool HasTag(string tagValue)
        {
            bool hasTag = false;

            XElement xml;
            lock (m_SyncLocker)
            {
                xml = XElement.Load(r_TagsXMLPath);
            }
            var q = xml.Elements("Tag").Where(u => u.Value == tagValue);
            if (q.Count() >= 1)
            {
                hasTag = true;
            }

            return hasTag;

        }

        public bool HasTag(string tagValue, out Tag tag)
        {
            bool hasTag = false;
            tag = null;

            XElement xml;
            lock (m_SyncLocker)
            {
                xml = XElement.Load(r_TagsXMLPath);
            }
            var q = xml.Elements("Tag").Where(u => u.Value == tagValue);
            if (q.Count() >= 1)
            {
                tag = TagsFactory.GetTag(q.ElementAt(0).Value);
                hasTag = true;
            }
            return hasTag;

        }

        #region add tags to document
        public void AddAcceptedTagToDocument(Document doc, Tag tag)
        {
            string path = doc.FilePath;
            string fileName = doc.FileName;
            XElement xml;
            lock (m_SyncLocker)
            {
                xml = XElement.Load(r_DocumentsXMLPath);
            }
            var q = from c in xml.Descendants("Document")
                    where (string)c.Element("Path") == path
                       && (string)c.Element("FileName") == fileName
                    select c;

            if (q.Count() > 0)
            {
                XElement tagElm = new XElement("Tag", tag.Name);

                q.ElementAt(0).Element("AcceptedTags").Add(tagElm);
            }

            lock (m_SyncLocker)
            {
                xml.Save(r_DocumentsXMLPath);
            }
        }

        public void AddSuggestedTagToDocument(Document doc, Tag tag)
        {
            string path = doc.FilePath;
            string fileName = doc.FileName;
            XElement xml;
            lock (m_SyncLocker)
            {
                xml = XElement.Load(r_DocumentsXMLPath);
            }
            var q = from c in xml.Descendants("Document")
                    where (string)c.Element("Path") == path
                       && (string)c.Element("FileName") == fileName
                    select c;

            if (q.Count() > 0)
            {
                XElement tagElm = new XElement("Tag", tag.Name);

                q.ElementAt(0).Element("SuggestedTags").Add(tagElm);
            }

            lock (m_SyncLocker)
            {
                xml.Save(r_DocumentsXMLPath);
            }
        }

        public void AddDeclinedTagToDocument(Document doc, Tag tag)
        {
            string path = doc.FilePath;
            string fileName = doc.FileName;
            XElement xml;
            lock (m_SyncLocker)
            {
                xml = XElement.Load(r_DocumentsXMLPath);
            }
            var q = from c in xml.Descendants("Document")
                    where (string)c.Element("Path") == path
                       && (string)c.Element("FileName") == fileName
                    select c;

            if (q.Count() > 0)
            {
                XElement tagElm = new XElement("Tag", tag.Name);

                q.ElementAt(0).Element("DeclinedTags").Add(tagElm);
            }

            lock (m_SyncLocker)
            {
                xml.Save(r_DocumentsXMLPath);
            }
        }
        #endregion


        #region remove tags from document
        public void RemoveAcceptedTagFromDocument(Document doc, Tag tag)
        {
            string path = doc.FilePath;
            string fileName = doc.FileName;
            string tagName = tag.Name;
            XElement xml;
            lock (m_SyncLocker)
            {
                xml = XElement.Load(r_DocumentsXMLPath);
            }
            var q = from c in xml.Descendants("Document")
                    where (string)c.Element("Path") == path
                        && (string)c.Element("FileName") == fileName
                    select c;

            if (q.Count() != 0)
            {
                int i = 0;
                foreach (XElement elm in q.ElementAt(0).Element("AcceptedTags").Elements("Tag"))
                {
                    if (elm.Value == tag.Name)
                    {
                        elm.Remove();
                        break;
                    }
                    i++;
                }
            }

            lock (m_SyncLocker)
            {
                xml.Save(r_DocumentsXMLPath);
            }
        }

        public void RemoveDeclinedTagFromDocument(Document doc, Tag tag)
        {
            string path = doc.FilePath;
            string fileName = doc.FileName;
            string tagName = tag.Name;
            XElement xml;
            lock (m_SyncLocker)
            {
                xml = XElement.Load(r_DocumentsXMLPath);
            }

            var q = from c in xml.Descendants("Document")
                    where (string)c.Element("Path") == path
                        && (string)c.Element("FileName") == fileName
                    select c;

            if (q.Count() != 0)
            {
                int i = 0;
                foreach (XElement elm in q.ElementAt(0).Element("DeclinedTags").Elements("Tag"))
                {
                    if (elm.Value == tag.Name)
                    {
                        elm.Remove();
                        break;
                    }
                    i++;
                }
            }

            lock (m_SyncLocker)
            {
                xml.Save(r_DocumentsXMLPath);
            }
        }

        public void DeclineSuggestedTagFromDocument(Document doc, Tag tag)
        {
            string path = doc.FilePath;
            string fileName = doc.FileName;
            string tagName = tag.Name;
            XElement xml;
            lock (m_SyncLocker)
            {
                xml = XElement.Load(r_DocumentsXMLPath);
            }
            var q = from c in xml.Descendants("Document")
                    where (string)c.Element("Path") == path
                        && (string)c.Element("FileName") == fileName
                    select c;

            if (q.Count() != 0)
            {
                int i = 0;
                foreach (XElement elm in q.ElementAt(0).Element("SuggestedTags").Elements("Tag"))
                {
                    if (elm.Value == tag.Name)
                    {
                        elm.Remove();
                        break;
                    }
                    i++;
                }
            }

            lock (m_SyncLocker)
            {
                xml.Save(r_DocumentsXMLPath);
            }
        }
        #endregion


        #region get documents tags
        public List<Tag> GetDocumentDeclinedTags(Document document)
        {
            List<Tag> res = new List<Tag>();
            XElement xml;
            lock (m_SyncLocker)
            {
                xml = XElement.Load(r_DocumentsXMLPath);
            }
            var q = xml.Elements("Document").Where((v) => (v.Element("FileName").Value == document.FileName && v.Element("Path").Value == document.FilePath));
            if (q.Count() == 1)
            {
                XElement doc = q.First();

                foreach (XElement xmlTag in doc.Elements("DeclinedTags").Elements("Tag"))
                {
                    res.Add(TagsFactory.GetTag(xmlTag.Value));
                }

            }

            return res;
        }

        public List<Tag> GetDocumentSuggestedTags(Document document)
        {
            List<Tag> res = new List<Tag>();
            XElement xml;
            lock (m_SyncLocker)
            {
                xml = XElement.Load(r_DocumentsXMLPath);
            }
            var q = xml.Elements("Document").Where((v) => (v.Element("FileName").Value == document.FileName && v.Element("Path").Value == document.FilePath));
            if (q.Count() == 1)
            {
                XElement doc = q.First();

                foreach (XElement xmlTag in doc.Elements("SuggestedTags").Elements("Tag"))
                {
                    res.Add(TagsFactory.GetTag(xmlTag.Value));
                }

            }

            return res;
        }

        public List<Tag> GetDocumentAcceptedTags(Document document)
        {
            List<Tag> res = new List<Tag>();
            XElement xml;
            lock (m_SyncLocker)
            {
                xml = XElement.Load(r_DocumentsXMLPath);
            }
            var q = xml.Elements("Document").Where((v) => (v.Element("FileName").Value == document.FileName && v.Element("Path").Value == document.FilePath));
            if (q.Count() == 1)
            {
                XElement doc = q.First();

                foreach (XElement xmlTag in doc.Elements("AcceptedTags").Elements("Tag"))
                {
                    res.Add(TagsFactory.GetTag(xmlTag.Value));
                }

            }

            return res;
        }
        #endregion


        public void RemoveSuggestedTagFromDocument(Document document, Tag tag)
        {
            string path = document.FilePath;
            string fileName = document.FileName;
            string tagName = tag.Name;
            XElement xml;
            lock (m_SyncLocker)
            {
                xml = XElement.Load(r_DocumentsXMLPath);
            }
            var q = from c in xml.Descendants("Document")
                    where (string)c.Element("Path") == path
                        && (string)c.Element("FileName") == fileName
                    select c;

            if (q.Count() != 0)
            {
                int i = 0;
                foreach (XElement elm in q.ElementAt(0).Element("SuggestedTags").Elements("Tag"))
                {
                    if (elm.Value == tag.Name)
                    {
                        elm.Remove();
                        break;
                    }
                    i++;
                }
            }

            lock (m_SyncLocker)
            {
                xml.Save(r_DocumentsXMLPath);
            }
        }
        #endregion

        #endregion

        #region private methods
        private string GetTagsXmlPath(string appDataDir)
        {
            string filePath = Path.Combine(appDataDir, TAG_XML_FILENAME);

            if (!File.Exists(filePath))
            {
                CreateEmptyTagsXmlFile(filePath);
            }
            return filePath;
        }

        private string GetDocumentsXmlPath(string appDataDir)
        {
            string filePath = Path.Combine(appDataDir, DOCUMENTS_XML_FILENAME);
            if (!File.Exists(filePath))
            {
                CreateEmptyDocumentsXmlFile(filePath);
            }
            return filePath;
        }

        private string GetConfigurationXmlPath(string appDataDir)
        {
            string filePath = Path.Combine(appDataDir, CONFIGURATION_XML_FILENAME);
            if (!File.Exists(filePath))
            {
                CreateEmptyConfigXmlFile(filePath);
            }
            return filePath;
        }

        /// <summary>
        /// creates an empty xml file containing the tags data
        /// </summary>
        /// <param name="filePath">The location to create the file</param>
        private void CreateEmptyTagsXmlFile(string filePath)
        {
            XDocument doc = new XDocument(
            new XDeclaration("1.0", "utf-8", "yes"),
                new XElement("Tags")
            );

            lock (m_SyncLocker)
            {
                doc.Save(filePath);
            }
        }

        /// <summary>
        /// creates an empty xml file containing the documents data
        /// </summary>
        /// <param name="filePath">The location to create the file</param>
        private void CreateEmptyDocumentsXmlFile(string filePath)
        {
            XDocument doc = new XDocument(
            new XDeclaration("1.0", "utf-8", "yes"),
                new XElement("Documents")
            );

            lock (m_SyncLocker)
            {
                doc.Save(filePath);
            }
        }

        /// <summary>
        /// creates an empty xml file containing the config data
        /// </summary>
        /// <param name="filePath">The location to create the file</param>
        private void CreateEmptyConfigXmlFile(string filePath)
        {
            XDocument doc = new XDocument(
            new XDeclaration("1.0", "utf-8", "yes"),
            new XElement("Config",
                new XElement("ScannedDirectories")
                )
             );

            lock (m_SyncLocker)
            {
                doc.Save(filePath);
            }
        }

        private string GetUserDataPath()
        {
            string dir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
            dir = System.IO.Path.Combine(dir, APP_FOLDER_NAME);
            if (!Directory.Exists(dir))
                Directory.CreateDirectory(dir);
            return dir;
        }
        
        #endregion


       
       

    }
}
